package com.gitee.cashzhang27.test.boot.reactive.webflux.handler;

import com.gitee.cashzhang27.test.boot.reactive.webflux.dao.CityMapRepository;
import com.gitee.cashzhang27.test.boot.reactive.webflux.entity.City;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * 城市处理器
 *
 *
 * Mono 和 Flux 适用于两个场景，即： Mono：实现发布者，并返回 0 或 1 个元素，即单对象。
 * Flux：实现发布者，并返回 N 个元素，即 List 列表对象。
 * 有人会问，这为啥不直接返回对象，比如返回 City/Long/List。
 * 原因是，直接使用 Flux 和 Mono 是非阻塞写法，相当于回调方式。
 * 利用函数式可以减少了回调，因此会看不到相关接口。这恰恰是 WebFlux 的好处：集合了非阻塞 + 异步
 *
 * Mono 常用的方法有：
 *
 * Mono.create()：使用 MonoSink 来创建 Mono。
 * Mono.justOrEmpty()：从一个 Optional 对象或 null 对象中创建 Mono。
 * Mono.error()：创建一个只包含错误消息的 Mono。
 * Mono.never()：创建一个不包含任何消息通知的 Mono。
 * Mono.delay()：在指定的延迟时间之后，创建一个 Mono，产生数字 0 作为唯一值
 *
 * 如果知道 Publisher 是 0 或 1 个，则用 Mono。
 *
 * Flux 最值得一提的是 fromIterable 方法，fromIterable(Iterable<? extends T> it)
 * 可以发布 Iterable 类型的元素。
 * 当然，Flux 也包含了基础的操作：map、merge、concat、flatMap、take等
 *
 * @author Cash Zhang
 * @version v1.0
 * @since 2019/03/28 15:32
 */
@Component
public class CityHandler {

  /**
   * 数据操作的dao层的bean
   */
  private final CityMapRepository cityMapRepository;

  /**
   * 通过构造器注入初始化属性cityRepository
   */
  @Autowired
  public CityHandler(CityMapRepository cityMapRepository) {
    this.cityMapRepository = cityMapRepository;
  }

  /**
   * 保存城市数据的处理方法
   */
  public Mono<Long> save(City city) {
    return Mono.create(cityMonoSink -> cityMonoSink.success(cityMapRepository.save(city)));
  }

  /**
   * 通过城市id查询城市的处理方法
   */
  public Mono<City> findCityById(Long id) {
    return Mono.justOrEmpty(cityMapRepository.findCityById(id));
  }

  /**
   * 查询所有城市数据
   */
  public Flux<City> findAllCity() {
    return Flux.fromIterable(cityMapRepository.findAll());
  }

  /**
   * 修改城市数据
   */
  public Mono<Long> modifyCity(City city) {
    return Mono.create(cityMonoSink -> cityMonoSink.success(cityMapRepository.updateCity(city)));
  }

  /**
   * 根据城市id删除城市数据
   */
  public Mono<Long> deleteCity(Long id) {
    return Mono.create(cityMonoSink -> cityMonoSink.success(cityMapRepository.deleteCity(id)));
  }

}
